/**

 @Name：layui.transfer 穿梭框
 @Author：贤心
 @License：MIT

 */

layui.define(['laytpl', 'form'], function (exports) {
    "use strict";

    var $ = layui.$
        , laytpl = layui.laytpl
        , form = layui.form

        //模块名
        , MOD_NAME = 'transferex'

        //外部接口
        , transfer = {
            config: {}
            , index: layui[MOD_NAME] ? (layui[MOD_NAME].index + 10000) : 0

            //设置全局项
            , set: function (options) {
                var that = this;
                that.config = $.extend({}, that.config, options);
                return that;
            }

            //事件监听
            , on: function (events, callback) {
                return layui.onevent.call(this, MOD_NAME, events, callback);
            }
        }

        //操作当前实例
        , thisModule = function () {
            var that = this
                , options = that.config
                , id = options.id || that.index;

            thisModule.that[id] = that; //记录当前实例对象
            thisModule.config[id] = options; //记录当前实例配置项

            return {
                config: options
                //重置实例
                , reload: function (options) {
                    that.reload.call(that, options);
                }
                //获取右侧数据
                , getData: function () {
                    return that.getData.call(that);
                }
            }
        }

        //获取当前实例配置项
        , getThisModuleConfig = function (id) {
            var config = thisModule.config[id];
            if (!config) hint.error('The ID option was not found in the ' + MOD_NAME + ' instance');
            return config || null;
        }

        //字符常量
        , ELEM = 'layui-transfer', HIDE = 'layui-hide', DISABLED = 'layui-btn-disabled', NONE = 'layui-none'
        , ELEM_BOX = 'layui-transfer-box', ELEM_HEADER = 'layui-transfer-header', ELEM_SEARCH = 'layui-transfer-search',
        ELEM_ACTIVE = 'layui-transfer-active', ELEM_DATA = 'layui-transfer-data'

        //穿梭框模板
        , TPL_BOX = function (obj) {
            obj = obj || {};
            return ['<div class="layui-transfer-box" data-index="' + obj.index + '">'
                , '<div class="layui-transfer-header">'
                , '<input type="checkbox" name="' + obj.checkAllName + '" lay-filter="layTransferCheckbox" lay-type="all" lay-skin="primary" title="{{ d.data.title[' + obj.index + '] || \'list' + (obj.index + 1) + '\' }}">'
                , '</div>'
                , '{{# if(d.data.showSearch){ }}'
                , '<div class="layui-transfer-search">'
                , '<i class="layui-icon layui-icon-search"></i>'
                , '<input type="input" class="layui-input" placeholder="关键词搜索">'
                , '</div>'
                , '{{# } }}'
                , '<ul class="layui-transfer-data"></ul>'
                , '</div>'].join('');
        }

        //主模板
        , TPL_MAIN = ['<div class="layui-transfer layui-form layui-border-box" lay-filter="LAY-transfer-{{ d.index }}">'
            , TPL_BOX({
                index: 0
                , checkAllName: 'layTransferLeftCheckAll'
            })
            , '<div class="layui-transfer-active">'
            , '<button type="button"  style="margin-bottom: 15px" eventType="to-first" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="1">'
            , '<i class="iconfont icon-layui-extend-first"></i>'
            , '</button>'
            , '<button type="button" style="margin-bottom: 15px" eventType="to-up" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="1">'
            , '<i class="layui-icon layui-icon-up"></i>'
            , '</button>'
            , '<button type="button" style="margin-bottom: 15px"  eventType="to-right" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="0">'
            , '<i class="layui-icon layui-icon-next"></i>'
            , '</button>'
            , '<button type="button" style="margin-bottom: 15px" eventType="to-left"  class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="1">'
            , '<i class="layui-icon layui-icon-prev"></i>'
            , '</button>'
            , '<button type="button" style="margin-bottom: 15px" eventType="to-down" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="1">'
            , '<i class="layui-icon layui-icon-down"></i>'
            , '</button>'
            , '<button type="button" eventType="to-last" class="layui-btn layui-btn-sm layui-btn-primary layui-btn-disabled" data-index="1">'
            , '<i class="iconfont icon-layui-extend-last"></i>'
            , '</button>'
            , '</div>'
            , TPL_BOX({
                index: 1
                , checkAllName: 'layTransferRightCheckAll'
            })
            , '</div>'].join('')

        //构造器
        , Class = function (options) {
            var that = this;
            that.index = ++transfer.index;
            that.config = $.extend({}, that.config, transfer.config, options);
            that.render();
        };

    //默认配置
    Class.prototype.config = {
        title: ['列表一', '列表二']
        , width: 200
        , height: 360
        , data: [] //数据源
        , value: [] //选中的数据
        , showSearch: false //是否开启搜索
        , id: '' //唯一索引，默认自增 index
        , text: {
            none: '无数据'
            , searchNone: '无匹配数据'
        },
        remove: false
        , onRemove: undefined
    };

    //重载实例
    Class.prototype.reload = function (options) {
        var that = this;

        layui.each(options, function (key, item) {
            if (item.constructor === Array) delete that.config[key];
        });

        that.config = $.extend(true, {}, that.config, options);
        that.render();
    };

    //渲染
    Class.prototype.render = function () {
        var that = this
            , options = that.config;

        //解析模板
        var thisElem = that.elem = $(laytpl(TPL_MAIN).render({
            data: options
            , index: that.index //索引
        }));

        var othis = options.elem = $(options.elem);
        if (!othis[0]) return;

        //初始化属性
        options.data = options.data || [];
        options.value = options.value || [];

        //索引
        that.key = options.id || that.index;

        //插入组件结构
        othis.html(that.elem);

        //各级容器
        that.layBox = that.elem.find('.' + ELEM_BOX)
        that.layHeader = that.elem.find('.' + ELEM_HEADER)
        that.laySearch = that.elem.find('.' + ELEM_SEARCH)
        that.layData = thisElem.find('.' + ELEM_DATA);
        that.layBtn = thisElem.find('.' + ELEM_ACTIVE + ' .layui-btn');

        //初始化尺寸
        that.layBox.css({
            width: options.width
            , height: options.height
        });
        that.layData.css({
            height: function () {
                return options.height - that.layHeader.outerHeight() - that.laySearch.outerHeight() - 2
            }()
        });

        that.renderData(); //渲染数据
        that.events(); //事件
    };

    //渲染数据
    Class.prototype.renderData = function () {
        var that = this
            , options = that.config;

        //左右穿梭框差异数据
        var arr = [{
            checkName: 'layTransferLeftCheck'
            , views: []
        }, {
            checkName: 'layTransferRightCheck'
            , views: []
        }];

        //解析格式
        that.parseData(function (item) {
            //标注为 selected 的为右边的数据
            var _index = item.selected ? 1 : 0;
            var listElem = ['<li>'
                , '<input type="checkbox" name="' + arr[_index].checkName + '" lay-skin="primary" lay-filter="layTransferCheckbox" title="' + item.title + '"' + (item.disabled ? ' disabled' : '') + (item.checked ? ' checked' : '') + ' value="' + item.value + '">'
            ];

            if (options.remove) {
                listElem.push('<i class="layui-icon layui-icon-close transfer-close"></i>');
            }

            listElem.push('</li>');
            listElem = listElem.join('');
            arr[_index].views.push(listElem);
            delete item.selected;
        });

        that.layData.eq(0).html(arr[0].views.join(''));
        that.layData.eq(1).html(arr[1].views.join(''));

        that.renderCheckBtn();
    }

    //渲染表单
    Class.prototype.renderForm = function (type) {
        form.render(type, 'LAY-transfer-' + this.index);
    };

    //同步复选框和按钮状态
    Class.prototype.renderCheckBtn = function (obj) {
        var that = this
            , options = that.config;

        obj = obj || {};

        that.layBox.each(function (_index) {
            var othis = $(this)
                , thisDataElem = othis.find('.' + ELEM_DATA)
                , allElemCheckbox = othis.find('.' + ELEM_HEADER).find('input[type="checkbox"]')
                , listElemCheckbox = thisDataElem.find('input[type="checkbox"]');

            //同步复选框和按钮状态
            var nums = 0
                , haveChecked = false;
            listElemCheckbox.each(function () {
                var isHide = $(this).data('hide');
                if (this.checked || this.disabled || isHide) {
                    nums++;
                }
                if (this.checked && !isHide) {
                    haveChecked = true;
                }
            });

            allElemCheckbox.prop('checked', haveChecked && nums === listElemCheckbox.length); //全选复选框状态
            that.layBtn.filter('[data-index="' + _index + '"]')[haveChecked ? 'removeClass' : 'addClass'](DISABLED);

            //无数据视图
            if (!obj.stopNone) {
                var isNone = thisDataElem.children('li:not(.' + HIDE + ')').length
                that.noneView(thisDataElem, isNone ? '' : options.text.none);
            }
        });

        that.renderForm('checkbox');

        //删除 事件
        that.layData.find('li .transfer-close').off('click');
        that.layData.find('li .transfer-close').on('click', function () {
            that.remove($(this).parent().find('input').val(), $(this).parents('.layui-transfer-box').attr('data-index'));
        })
    };

    //无数据视图
    Class.prototype.noneView = function (thisDataElem, text) {
        var createNoneElem = $('<p class="layui-none">' + (text || '') + '</p>');
        if (thisDataElem.find('.' + NONE)[0]) {
            thisDataElem.find('.' + NONE).remove();
        }
        text.replace(/\s/g, '') && thisDataElem.append(createNoneElem);
    };

    //同步 value 属性值
    Class.prototype.setValue = function () {
        var that = this
            , options = that.config
            , arr = [];
        that.layBox.eq(1).find('.' + ELEM_DATA + ' input[type="checkbox"]').each(function () {
            var isHide = $(this).data('hide');
            isHide || arr.push(this.value);
        });
        options.value = arr;

        return that;
    };

    //解析数据
    Class.prototype.parseData = function (callback) {
        var that = this
            , options = that.config
            , newData = [];

        layui.each(options.data, function (index, item) {
            //解析格式
            item = (typeof options.parseData === 'function'
                ? options.parseData(item)
                : item) || item;

            newData.push(item = $.extend({}, item))

            layui.each(options.value, function (index2, item2) {
                if (item2 == item.value) {
                    item.selected = true;
                }
            });
            callback && callback(item);
        });

        options.data = newData;
        return that;
    };

    /**
     * 添加数据 初始化后添加
     * @param data
     */
    Class.prototype.addData = function (data) {
        var that = this
            , options = that.config
            , unselectDataElem = that.layBox.eq(0).find('.' + ELEM_DATA);

        //解析格式
        data = (typeof options.parseData === 'function'
            ? options.parseData(data)
            : data) || data;

        layui.each(options.value, function (index2, item2) {
            if (item2 == data.value) {
                data.selected = true;
            }
        });

        //标注为 selected 的为右边的数据
        var listElem = ['<li>'
            , '<input type="checkbox" name="layTransferLeftCheck" lay-skin="primary" lay-filter="layTransferCheckbox" title="' + data.title + '"' + (data.disabled ? ' disabled' : '') + (data.checked ? ' checked' : '') + ' value="' + data.value + '">'
        ];
        if (options.remove) {
            listElem.push('<i class="layui-icon layui-icon-close transfer-close"></i>');
        }

        listElem.push('</li>');
        listElem = listElem.join('');
        delete data.selected;
        that.layData.eq(0).append(listElem);
        options.data.push(data = $.extend({}, data));
        that.renderForm('checkbox');
        that.renderCheckBtn();
        that.setValue();
        return that;
    }

    /**
     * @Description: 删除数据  data  和 value 都进行删除
     * @param:
     * @Return:
     * @Author: Z
     * @Date: 2019-12-16 17:15
     */
    Class.prototype.remove = function (value, boxindex) {
        var that = this
            , options = that.config
            , removeDataArry = []
            , removeValueArry = []
            , unselectDataElem = that.layBox.eq(0).find('.' + ELEM_DATA)
            , selectDataElem = that.layBox.eq(1).find('.' + ELEM_DATA);
        that.layBox.eq(0).find('.' + ELEM_DATA).children('li').find('input[type="checkbox"][value="' + value + '"]').parent().remove();
        that.layBox.eq(1).find('.' + ELEM_DATA).children('li').find('input[type="checkbox"][value="' + value + '"]').parent().remove();

        layui.each(options.data, function (index, item) {
            if (item.value == value) {
                removeDataArry.push(index);
            }
        });

        layui.each(removeDataArry, function (index, item) {
            //删除的回调
            if (boxindex == 0) {
                options.onRemove && options.onRemove([options.data[item]], 0);
            }
            options.data.splice(item, 1);
        });

        if (options.data.length == 0) {
            var isNone = unselectDataElem.children('li:not(.' + HIDE + ')').length
            that.noneView(unselectDataElem, isNone ? '' : options.text.none);
        }

        layui.each(options.value, function (index, item) {
            if (item == value) {
                removeValueArry.push(index);
            }
        });

        layui.each(removeValueArry, function (index, item) {
            //删除的回调
            if (boxindex == 1) {
                options.onRemove && options.onRemove(that.getData(options.value[item]), 1);
            }
            options.value.splice(item, 1);
        });

        if (options.value.length == 0) {
            var isNone = selectDataElem.children('li:not(.' + HIDE + ')').length
            that.noneView(selectDataElem, isNone ? '' : options.text.none);
        }

        that.renderCheckBtn();
        that.setValue();

        return that;
    }

    //获得右侧面板数据
    Class.prototype.getData = function (value) {
        var that = this
            , options = that.config
            , selectedData = [];

        that.setValue();

        layui.each(value || options.value, function (index, item) {
            layui.each(options.data, function (index2, item2) {
                delete item2.selected;
                if (item == item2.value) {
                    selectedData.push(item2);
                }
                ;
            });
        });
        return selectedData;
    };

    //事件
    Class.prototype.events = function () {
        var that = this
            , options = that.config;

        //左右复选框
        that.elem.on('click', 'input[lay-filter="layTransferCheckbox"]+', function () {
            var thisElemCheckbox = $(this).prev()
                , checked = thisElemCheckbox[0].checked
                , thisDataElem = thisElemCheckbox.parents('.' + ELEM_BOX).eq(0).find('.' + ELEM_DATA);

            if (thisElemCheckbox[0].disabled) return;

            //判断是否全选
            if (thisElemCheckbox.attr('lay-type') === 'all') {
                thisDataElem.find('input[type="checkbox"]').each(function () {
                    if (this.disabled) return;
                    this.checked = checked;
                });
            }

            that.renderCheckBtn({stopNone: true});
        });

        //按钮事件
        that.layBtn.on('click', function () {
            var othis = $(this)
                , _index = othis.data('index')
                , thisBoxElem = that.layBox.eq(_index)
                , arr = []
                , eventType = othis.attr('eventType');
            if (othis.hasClass(DISABLED)) return;

            that.layBox.eq(_index).each(function (_index) {
                var othis = $(this)
                    , thisDataElem = othis.find('.' + ELEM_DATA);

                //左右穿梭
                if (eventType == 'to-left' || eventType == 'to-right') {
                    thisDataElem.children('li').each(function () {
                        var thisList = $(this)
                            , thisElemCheckbox = thisList.find('input[type="checkbox"]')
                            , isHide = thisElemCheckbox.data('hide');

                        if (thisElemCheckbox[0].checked && !isHide) {
                            thisElemCheckbox[0].checked = false;
                            thisBoxElem.siblings('.' + ELEM_BOX).find('.' + ELEM_DATA).append(thisList.clone());
                            thisList.remove();

                            //记录当前穿梭的数据
                            arr.push(thisElemCheckbox[0].value);
                        }

                        that.setValue();
                    });
                } else {
                    switch (eventType) {
                        case 'to-up':
                            toUp();
                            break;
                        case 'to-first':
                            toFirst();
                            break;
                        case 'to-down':
                            toDown();
                            break;
                        case 'to-last':
                            tolast();
                            break;
                        default:
                            console.log('unknow eventType:' + eventType);
                            break;
                    }
                }
            });

            that.renderCheckBtn();

            //穿梭时，如果另外一个框正在搜索，则触发匹配
            var siblingInput = thisBoxElem.siblings('.' + ELEM_BOX).find('.' + ELEM_SEARCH + ' input')
            siblingInput.val() === '' || siblingInput.trigger('keyup');

            //穿梭时的回调
            options.onchange && options.onchange(that.getData(arr), _index);
        });

        //搜索
        that.laySearch.find('input').on('keyup', function () {
            var value = this.value
                , thisDataElem = $(this).parents('.' + ELEM_SEARCH).eq(0).siblings('.' + ELEM_DATA)
                , thisListElem = thisDataElem.children('li');

            thisListElem.each(function () {
                var thisList = $(this)
                    , thisElemCheckbox = thisList.find('input[type="checkbox"]')
                    , isMatch = thisElemCheckbox[0].title.indexOf(value) !== -1;

                thisList[isMatch ? 'removeClass' : 'addClass'](HIDE);
                thisElemCheckbox.data('hide', isMatch ? false : true);
            });

            that.renderCheckBtn();

            //无匹配数据视图
            var isNone = thisListElem.length === thisDataElem.children('li.' + HIDE).length;
            that.noneView(thisDataElem, isNone ? options.text.searchNone : '');
        });


        //上移
        function toUp() {
            //找到选中的li
            var index = that.layBox.eq(1).find('.' + ELEM_DATA).children('li').find('input[type="checkbox"]:checked').parent();
            if (index.length == 0) {
                layer.msg("请在右边框选中后，再进行移位操作");
                return;
            }
            for (var i = 0; i < index.length; i++) {
                if (index.eq(i).index() != 0) {
                    index.eq(i).prev().before(index.eq(i));
                }
            }
        }

        //置顶
        function toFirst() {
            //找到选中的li
            var index = that.layBox.eq(1).find('.' + ELEM_DATA).children('li').find('input[type="checkbox"]:checked').parent();
            if (index.length == 0) {
                layer.msg("请在右边框选中后，再进行移位操作");
                return;
            }
            for (var i = index.length - 1; i >= 0; i--) {
                do {
                    index.eq(i).prev().before(index.eq(i));
                } while (index.eq(i).index() != 0)
            }
        }

        //下移
        function toDown(dom) {
            //找到选中的li
            var index = that.layBox.eq(1).find('.' + ELEM_DATA).children('li').find('input[type="checkbox"]:checked').parent();
            if (index.length == 0) {
                layer.msg("请在右边框选中后，再进行移位操作");
                return;
            }
            for (var i = index.length - 1; i >= 0; i--) {
                if (index.eq(i).index() != that.config.value.length - 1) {
                    index.eq(i).next().after(index.eq(i));
                }
            }
        }

        //置底
        function tolast() {
            //找到选中的li
            var index = that.layBox.eq(1).find('.' + ELEM_DATA).children('li').find('input[type="checkbox"]:checked').parent();
            if (index.length == 0) {
                layer.msg("请在右边框选中后，再进行移位操作");
                return;
            }
            for (var i = 0; i < index.length; i++) {
                do {
                    index.eq(i).next().after(index.eq(i));
                } while (index.eq(i).index() != that.config.value.length - 1)
            }
        }
    };

    //记录所有实例
    thisModule.that = {}; //记录所有实例对象
    thisModule.config = {}; //记录所有实例配置项

    //重载实例
    transfer.reload = function (id, options) {
        var that = thisModule.that[id];
        that.reload(options);

        return thisModule.call(that);
    };

    //获得选中的数据（右侧面板）
    transfer.getData = function (id) {
        var that = thisModule.that[id];
        return that.getData();
    };

    //添加数据
    transfer.addData = function (data, id) {
        var that = thisModule.that[id];
        return that.addData(data);
    }

    //删除数据
    transfer.remove = function (value, id) {
        var that = thisModule.that[id];
        return that.remove(value);
    }

    //获取data数据
    transfer.getAllData = function (id) {
        var that = thisModule.that[id];
        return that.config.data;
    }

    //核心入口
    transfer.render = function (options) {
        var inst = new Class(options);
        return thisModule.call(inst);
    };

    exports(MOD_NAME, transfer);
});
